#ifndef __NODE_CCD_HH__
#define __NODE_CCD_HH__

#include <unistd.h>
#include <iostream>
#include <cstdlib>
#include <chrono>
#include <future>
#include <queue>
#include <list>
#include <map>
#include <atomic>

using namespace std;

#define CCD_HARDWARE_VERSION "0.0.0.1"
#define CCD_SOFTWARE_VERSION "0.0.0.1"
#define CCD_SN "1001"
#define CCD_NAME "rasp_ccd"
#define CCD_MODEL "rasp"

#define CCD_BROADCAST_PORT 7051
#define CCD_TCPSERVER_PORT 6051

#define CLIENT_TYPE_CCD 1
#define CLIENT_TYPE_APP 2
#define CLIENT_TYPE_ECD 3

#define MSG_FROM_CLOUD 1
#define MSG_FROM_APP   2
#define MSG_FROM_ECD   3
struct ecdevice_info
{
		int addr;
		string sn;
		string hardver;
		string firmver;
		string device;
		string name;
		string model;
};

class client_conn
{
		public:
				client_conn(){}
				~client_conn() { }
				void disconnect()
				{
						if(fd > 0) {::close(fd);fd = -1;}
				}
				client_conn(int _fd,int _type)
				{fd = _fd;type = _type;lastAliveTimepoint = std::chrono::high_resolution_clock::now();}

				void updateAlive()
				{lastAliveTimepoint = std::chrono::high_resolution_clock::now();}

				bool heartTime(int secs)
				{
					using namespace std::chrono;
					if(high_resolution_clock::now() - lastHeartTimepoint>= seconds(secs))
					{
							lastHeartTimepoint = high_resolution_clock::now();
							return true;
					}
					return false;
				}
				bool expired()
				{
					using namespace std::chrono;
					if(high_resolution_clock::now() - lastAliveTimepoint >= seconds(30))
					{
							return true;
					}
					return false;
				}
		int fd;
		int type;
		std::chrono::high_resolution_clock::time_point lastAliveTimepoint;
		std::chrono::high_resolution_clock::time_point lastHeartTimepoint;
		std::string inmsg;
		std::string outmsg;

		ecdevice_info ecdinfo;

		std::queue<string> inmsgs;
		std::queue<string> outmsgs;
};

class NodeCCD
{
	public:
		static	NodeCCD * getCCD();

	private:
		static NodeCCD * mSelf;

		NodeCCD();
		~NodeCCD();

	public:
		bool initEnv(string cloud,int port);
		bool begin();
		void addMsgToCloud(string msg);
		void addMsgToClient(string msg);

	private:
		bool handleMessage(client_conn& conn);
		bool reportTime(int id,int secs);

		string packBroadcastMsg();
		string packHeartbeatMsg();
		string packCloudloginMsg();
		string packReportData();

		void taskBroadcast();
		void taskTcpServer();
		void taskTcpClouds();
		void taskNanoEvent();

	private:
		int mECDCurAddr;

		string mCloudServer;
		int mCloudPort;

		int mBroadcastPort;
		int mTcpServerPort;

		int mTcpServerFd;

		// 0 - Report to Cloud, 1 - Report to online-APPs
		//std::atomic<bool> mReportFlag[2];
		bool mReportFlag[2];
		std::chrono::high_resolution_clock::time_point mLastReportTimepoint[2];

		client_conn mCloudClient;
		std::list<client_conn> mAppClients;

		std::map<int,std::queue<string>> mToECDMsgs; // <addr,msgs>
		std::queue<string> mToCloudMsgs;
		std::queue<string> mToClientMsgs;

		std::future<void> mBroadcastTask;
		std::future<void> mTcpServerTask;
		std::future<void> mTcpCloudsTask;
		std::future<void> mNanoEventTask;
};

#endif

